/*
 * Copyright (C) 2013 Maciej Górski
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.seguriapp.activities;

import java.text.Collator;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import pl.mg6.android.maps.extensions.Circle;
import pl.mg6.android.maps.extensions.ClusteringSettings;
import pl.mg6.android.maps.extensions.GoogleMap;
import pl.mg6.android.maps.extensions.GoogleMap.InfoWindowAdapter;
import pl.mg6.android.maps.extensions.GoogleMap.OnInfoWindowClickListener;
import pl.mg6.android.maps.extensions.GoogleMap.OnMapClickListener;
import pl.mg6.android.maps.extensions.Marker;
import pl.mg6.android.maps.extensions.SupportMapFragment;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Color;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.LatLngBounds.Builder;
import com.google.android.gms.maps.model.MarkerOptions;
import com.seguriapp.R;
import com.seguriapp.controllers.CrimeController;
import com.seguriapp.dialogs.SelectCategoryDialog;
import com.seguriapp.entities.CrimeEntity;
import com.seguriapp.other.CategoryDialogInterface;
import com.seguriapp.util.DemoIconProvider;

public class CrimeMapFragmentActivity extends FragmentActivity implements
		CategoryDialogInterface {

	private static final double[] CLUSTER_SIZES = new double[] { 180, 160, 144,
			120, 96 };

	private GoogleMap map;
	private ProgressDialog dialog;

	private Context mContext;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.demo);
		mContext = this;
		FragmentManager fm = getSupportFragmentManager();
		SupportMapFragment f = (SupportMapFragment) fm
				.findFragmentById(R.id.map);
		map = f.getExtendedMap();

		map.setOnMapClickListener(new OnMapClickListener() {

			@Override
			public void onMapClick(LatLng position) {
				for (Circle circle : map.getCircles()) {
					if (circle.contains(position)) {
						Toast.makeText(CrimeMapFragmentActivity.this,
								"Clicked " + circle.getData(),
								Toast.LENGTH_SHORT).show();
						return;
					}
				}
			}
		});

		map.setClustering(new ClusteringSettings().iconDataProvider(
				new DemoIconProvider(getResources())).addMarkersDynamically(
				true));

		map.setInfoWindowAdapter(new InfoWindowAdapter() {

			private TextView tv;
			{
				tv = new TextView(CrimeMapFragmentActivity.this);
				tv.setTextColor(Color.BLACK);
			}

			private Collator collator = Collator.getInstance();
			private Comparator<Marker> comparator = new Comparator<Marker>() {
				public int compare(Marker lhs, Marker rhs) {
					String leftTitle = lhs.getTitle();
					String rightTitle = rhs.getTitle();
					if (leftTitle == null && rightTitle == null) {
						return 0;
					}
					if (leftTitle == null) {
						return 1;
					}
					if (rightTitle == null) {
						return -1;
					}
					return collator.compare(leftTitle, rightTitle);
				}
			};

			@Override
			public View getInfoWindow(Marker marker) {
				return null;
			}

			@Override
			public View getInfoContents(Marker marker) {
				if (marker.isCluster()) {
					HashMap<String, Integer> markerMap = new HashMap<String, Integer>();
					List<Marker> markers = marker.getMarkers();
					for (int j = 0; j < markers.size(); j++) {
						Marker markerSon = markers.get(j);
						if (markerMap.containsKey(markerSon.getTitle())) {
							markerMap.put(markerSon.getTitle(),
									markerMap.get(markerSon.getTitle()) + 1);
						} else {
							markerMap.put(markerSon.getTitle(), 1);
						}
					}

					String text = "";
					Iterator it = markerMap.entrySet().iterator();
					while (it.hasNext()) {
						Map.Entry pairs = (Map.Entry) it.next();
						String title = (String) pairs.getKey();
						text += pairs.getValue().toString() + " " + title
								+ "\n";

						it.remove(); // avoids a ConcurrentModificationException
					}

					// int i = 0;
					//
					// while (i < 3 && markers.size() > 0) {
					// Marker m = Collections.min(markers, comparator);
					// String title = m.getTitle();
					// if (title == null) {
					// break;
					// }
					// text += title + "\n";
					// markers.remove(m);
					// i++;
					// }
					// if (text.length() == 0) {
					// text = "Markers with mutable data";
					// } else if (markers.size() > 0) {
					// text += "and " + markers.size() + " more...";
					// } else {
					// text = text.substring(0, text.length() - 1);
					// }
					tv.setText(text);
					return tv;
				} else {
					Object data = marker.getData();
					if (data instanceof MutableData) {
						MutableData mutableData = (MutableData) data;
						tv.setText("Value: " + mutableData.value);
						return tv;
					}
				}

				return null;
			}
		});

		map.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {

			@Override
			public void onInfoWindowClick(Marker marker) {
				if (marker.isCluster()) {
					List<Marker> markers = marker.getMarkers();
					Builder builder = LatLngBounds.builder();
					for (Marker m : markers) {
						builder.include(m.getPosition());
					}
					LatLngBounds bounds = builder.build();
					map.animateCamera(CameraUpdateFactory.newLatLngBounds(
							bounds,
							getResources().getDimensionPixelSize(
									R.dimen.padding)));
				}
			}
		});

		setUpClusteringViews();
	}

	private void comenzarDialogo() {
		dialog = ProgressDialog.show(mContext, "",
				getText(R.string.msgLoading), true, true, null);
		dialog.show();
	}

	@Override
	protected void onResume() {
		super.onResume();
		final LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
		final Criteria criteria = new Criteria();
		final String provider = service.getBestProvider(criteria, false);
		final Location location = service.getLastKnownLocation(provider);
		final LatLng userLocation = new LatLng(location.getLatitude(),
				location.getLongitude());
		map.animateCamera(CameraUpdateFactory.newLatLngZoom(userLocation, 13));
		obtenerCrimenes();
	}

	@Override
	protected void onPause() {
		super.onPause();
	}

	private void onDataUpdate() {
		Marker m = map.getMarkerShowingInfoWindow();
		if (m != null && !m.isCluster() && m.getData() instanceof MutableData) {
			m.showInfoWindow();
		}
	}

	void updateClustering(int clusterSizeIndex, boolean enabled) {
		ClusteringSettings clusteringSettings = new ClusteringSettings();
		clusteringSettings.addMarkersDynamically(true);

		if (enabled) {
			clusteringSettings.iconDataProvider(new DemoIconProvider(
					getResources()));

			double clusterSize = CLUSTER_SIZES[clusterSizeIndex];
			clusteringSettings.clusterSize(clusterSize);
		} else {
			clusteringSettings.enabled(false);
		}
		map.setClustering(clusteringSettings);
	}

	private static class MutableData {

		private int value;

		private LatLng position;

		public MutableData(int value, LatLng position) {
			this.value = value;
			this.position = position;
		}
	}

	@Override
	public void onChangeCategories() {
		comenzarDialogo();
		map.clear();
		obtenerCrimenes();
		// mapView.invalidate();
	}

	private void obtenerCrimenes() {
		comenzarDialogo();
		new Thread(new Runnable() {
			@Override
			public void run() {
				final CrimeController cController = new CrimeController(
						mContext);
				final List<CrimeEntity> items = cController
						.getCrimeList(cController.getSelectedCategories(true));

				runOnUiThread(new Runnable() {

					@Override
					public void run() {
						if (items == null) {
							Toast.makeText(mContext,
									"No hay categorías seleccionadas.",
									Toast.LENGTH_SHORT).show();

						} else {
							updateLocations(items);
							updateClustering(2, true);
						}
					}
				});

				cerrarDialogo();
			}
		}).start();
	}

	private void cerrarDialogo() {
		dialog.dismiss();
	}

	public void updateLocations(List<CrimeEntity> items) {
		MarkerOptions options = new MarkerOptions();
		for (int i = 0; i < items.size(); i++) {
			map.addMarker(options.title(items.get(i).getCategory().getName())
					.position(
							new LatLng(items.get(i).getLatitude(), items.get(i)
									.getLongitude())));
		}
		// final CrimeOverlay afpOverlay = new CrimeOverlay(mContext,
		// getResources().getDrawable(R.drawable.actualpos), items);
		// mapView.getOverlays().add(afpOverlay);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		final MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.select_crime_categories, menu);
		return super.onCreateOptionsMenu(menu);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.select_category_menu:
			final FragmentManager fm = getSupportFragmentManager();
			final SelectCategoryDialog categoryDialog = new SelectCategoryDialog(
					this, SelectCategoryDialog.CRIME_CATEGORY);
			categoryDialog.show(fm, "category_dialog");
			break;
		default:
			break;
		}
		return super.onOptionsItemSelected(item);
	}

	private void setUpClusteringViews() {
		CheckBox clusterCheckbox = (CheckBox) findViewById(R.id.checkbox_cluster);
		final SeekBar clusterSizeSeekbar = (SeekBar) findViewById(R.id.seekbar_cluster_size);
		clusterCheckbox
				.setOnCheckedChangeListener(new OnCheckedChangeListener() {

					@Override
					public void onCheckedChanged(CompoundButton buttonView,
							boolean isChecked) {
						clusterSizeSeekbar.setEnabled(isChecked);

						updateClustering(clusterSizeSeekbar.getProgress(),
								isChecked);
					}
				});
		clusterSizeSeekbar
				.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

					@Override
					public void onStartTrackingTouch(SeekBar seekBar) {
					}

					@Override
					public void onProgressChanged(SeekBar seekBar,
							int progress, boolean fromUser) {
						updateClustering(progress, true);
					}

					@Override
					public void onStopTrackingTouch(SeekBar seekBar) {
					}
				});

		final Button categoriesButton = (Button) findViewById(R.id.catButton);
		categoriesButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				final FragmentManager fm = getSupportFragmentManager();
				final SelectCategoryDialog categoryDialog = new SelectCategoryDialog(
						CrimeMapFragmentActivity.this,
						SelectCategoryDialog.CRIME_CATEGORY);
				categoryDialog.show(fm, "category_dialog");
			}
		});
	}
}
